/**
 *
 */

package com.yuan.unit;

import com.yuan.prefence.FileConstants;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.provider.SyncStateContract.Constants;
import android.text.TextUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 有关文件操作的工具。
 * 
 * @author YUAN
 */
public class FileUtils {

    public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();
    private static String TAG = "FileUtil";
    /***
     * SD目录
     */
    static {
        initAllFileType(); // 初始化文件类型信息
    }

    private static void initAllFileType()
    {
        FILE_TYPE_MAP.put("jpg", "FFD8FF"); // JPEG (jpg)
        FILE_TYPE_MAP.put("png", "89504E47"); // PNG (png)
        FILE_TYPE_MAP.put("gif", "47494638"); // GIF (gif)
        FILE_TYPE_MAP.put("tif", "49492A00"); // TIFF (tif)
        FILE_TYPE_MAP.put("bmp", "424D"); // Windows Bitmap (bmp)
        FILE_TYPE_MAP.put("dwg", "41433130"); // CAD (dwg)
        FILE_TYPE_MAP.put("html", "68746D6C3E"); // HTML (html)
        FILE_TYPE_MAP.put("rtf", "7B5C727466"); // Rich Text Format (rtf)
        FILE_TYPE_MAP.put("xml", "3C3F786D6C");
        FILE_TYPE_MAP.put("zip", "504B0304");
        FILE_TYPE_MAP.put("rar", "52617221");
        FILE_TYPE_MAP.put("psd", "38425053"); // Photoshop (psd)
        FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A"); // Email
        FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F"); // Outlook Express (dbx)
        FILE_TYPE_MAP.put("pst", "2142444E"); // Outlook (pst)
        FILE_TYPE_MAP.put("xls", "D0CF11E0"); // MS Word
        FILE_TYPE_MAP.put("doc", "D0CF11E0"); // MS Excel 注意：word 和 excel的文件头一样
        FILE_TYPE_MAP.put("mdb", "5374616E64617264204A"); // MS Access (mdb)
        FILE_TYPE_MAP.put("wpd", "FF575043"); // WordPerfect (wpd)
        FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("pdf", "255044462D312E"); // Adobe Acrobat (pdf)
        FILE_TYPE_MAP.put("qdf", "AC9EBD8F"); // Quicken (qdf)
        FILE_TYPE_MAP.put("pwl", "E3828596"); // Windows Password (pwl)
        FILE_TYPE_MAP.put("wav", "57415645"); // Wave (wav)
        FILE_TYPE_MAP.put("avi", "41564920");
        FILE_TYPE_MAP.put("ram", "2E7261FD"); // Real Audio (ram)
        FILE_TYPE_MAP.put("rm", "2E524D46"); // Real Media (rm)
        FILE_TYPE_MAP.put("mpg", "000001BA"); //
        FILE_TYPE_MAP.put("mov", "6D6F6F76"); // Quicktime (mov)
        FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); // Windows Media (asf)
        FILE_TYPE_MAP.put("mid", "4D546864"); // MIDI (mid)
    }

    public static boolean isImageFile(byte[] b) {
        String type = getFileTypeByStream(b);
        return "png".equals(type) || "jpg".equals(type) || "bmp".equals(type) || "gif".equals(type);
    }

    public FileUtils() {
    }

    public boolean isRootFileExist() {
        File file = new File(Constants.CONTENT_DIRECTORY);
        return file.exists();
    }

    /***
     * 在SD卡上创建文件
     * 
     * @param fileName 文件
     * @param dir 文件存储目录
     * @return 文件
     * @throws IOException
     */
    public static File createFileInSDCard(String filepath)
            throws IOException {
        File file = new File(filepath);
        if (file.exists())
        {
            file.delete();
        }
        file.createNewFile();
        return file;
    }

    /**
     * 在SD卡上创建目录
     * 
     * @param dir 目录名称
     * @return 返回目录
     */
    public static File createSDDir(String dirpath) {
        File dirFile = new File(dirpath);
        // System.out.println(dirFile);
        BLog.d(TAG, "创建目录路径为：" + dirpath);
        dirFile.mkdirs();
        return dirFile;
    }

    /***
     * 判断文件是否存在
     * 
     * @param fileNameString 文件
     * @param pathString 文件路径
     * @return 存在返回true 不存在返回false
     */
    public static boolean isFileExist(String filepath) {
        File file = new File(filepath);
        return file.exists();
    }

    /***
     * 将InputStream里面的数据写入到SD卡的文件
     * 
     * @param path 文件的路
     * @param fileNameString 文件
     * @param inputStream 数据
     * @return
     */
    public static File write2SDFromInput(String path, InputStream inputStream) {
        File file = null;
        OutputStream outputStream = null;
        try {
            file = createFileInSDCard(path);
            outputStream = new FileOutputStream(file);
            // 创建4*1024大小的缓冲区
            byte buffer[] = new byte[4 * 1024];
            int temp;
            // 循环读取InputStream里的数据
            while ((temp = inputStream.read(buffer)) != -1) {
                // 把流按照buffer的大小写入到文件
                outputStream.write(buffer, 0, temp);
            }
            // 提交缓冲区的内容
            outputStream.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();

            } catch (Exception e2) {
                // TODO: handle exception
                e2.printStackTrace();
            }
        }
        return file;
    }

    public static void write2SDFromString(String path, String str, String StringCode) {
        try {
            InputStream mInputStream = new ByteArrayInputStream(str.getBytes(StringCode));
            write2SDFromInput(path, mInputStream);
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @SuppressLint("DefaultLocale")
    public final static String getFileTypeByStream(byte[] b)
    {
        String filetypeHex = String.valueOf(getFileHexString(b));
        Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
        while (entryiterator.hasNext()) {
            Entry<String, String> entry = entryiterator.next();
            String fileTypeHexValue = entry.getValue();
            if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                return entry.getKey();
            }
        }
        return null;
    }

    public final static String getFileHexString(byte[] b)
    {
        StringBuilder stringBuilder = new StringBuilder();
        if (b == null || b.length <= 0)
        {
            return null;
        }
        for (int i = 0; i < b.length; i++)
        {
            int v = b[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2)
            {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 创建.NoMedia文件夹，如果路径存在的话则创建，否则不创建。 写自2011-10-28
     * 
     * @param path
     * @return
     * @throws IOException
     */
    public static boolean createNoMediaFileIfPathExists(String path) throws IOException {
        File file = new File(path);
        if (file.exists() && file.isDirectory()) {
            File noMediaFile = new File(path + ".nomedia");
            noMediaFile.mkdir();
            return true;
        }
        return false;
    }

    public static boolean mkdirs(File file) {
        String path = file.getPath();
        String moveTo = "/";
        String[] splits = path.split("/");
        for (String split : splits) {
            if (TextUtils.isEmpty(split)) {
                continue;
            }
            File file2 = new File(moveTo + File.separator + split);
            if (!file2.exists()) {
                if (!file2.mkdir()) {
                    return false;
                }
            }
            moveTo += File.separator + split;
        }

        return true;
    }

    /**
     * 判断外部存储（SD卡）是否可用。
     * 
     * @return
     */
    public static boolean isExternalStorageAvail() {
        // 解决“M9检查SD卡会失败”的问题 -Jiongxuan
        return android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);
    }

    private static final String SPKEY_ASSERT_PATH = "assert_path";

    /**
     * 获取存在本地的文件路径
     * 
     * @param context
     * @param fileName
     * @return
     */
    public static String getFilePathToSave(Context context, String fileName) {
        SharedPreferences preferences = PreferenceUtil.getInstance().pref();
        String fileDir = preferences.getString(SPKEY_ASSERT_PATH, null);
        if (TextUtils.isEmpty(fileDir)) {
            fileDir = context.getApplicationInfo().dataDir + "/assert";
            File dir = new File(fileDir);
            boolean isCreated = false;
            if (!dir.exists()) {
                try {
                    isCreated = dir.mkdir();
                } catch (Exception e) {
                    Utils.error(FileUtils.class, Utils.getStackTrace(e));
                    isCreated = false;
                }

                if (!isCreated) {
                    fileDir = context.getCacheDir().getPath() + "/assert_cache";
                    dir = new File(fileDir);
                    if (!dir.exists()) {
                        try {
                            isCreated = dir.mkdir();
                        } catch (Exception e) {
                            Utils.error(FileUtils.class, Utils.getStackTrace(e));
                            isCreated = false;
                        }
                        if (!isCreated)
                            return null;
                    }

                }
            }
            preferences.edit().putString(SPKEY_ASSERT_PATH, fileDir).commit();
        }

        return fileDir + "/" + fileName;
    }

    public static void copyRawToCache(Context context, int rawId, String fileName) {
        try {
            // 要把自带的json文件复制到Cache目录下，然后读取它
            InputStream in = context.getResources().openRawResource(rawId);
            String filePath = getFilePathToSave(context, fileName);
            if (TextUtils.isEmpty(filePath)) {
                return;
            }

            OutputStream out = new FileOutputStream(filePath);

            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }

            in.close();
            out.close();
        } catch (Exception e) {
            Utils.error(FileUtils.class, Utils.getStackTrace(e));
        }
    }

    public static String getTextFromReaderFile(Context context, int rawId, String fileName) {
        String jsonString = "";
        try {
            File file = new File(getFilePathToSave(context, fileName));
            if (!file.exists() && rawId != 0) {
                // 若没有新文件，且raw中有这个文件的话，则将其复制一份过去
                copyRawToCache(context, rawId, fileName);
                Utils.debug(FileUtils.class, "cache\\%s is not exists!", fileName);
            }

            BufferedInputStream bufferedInputStream = new BufferedInputStream(
                    new FileInputStream(file));
            long contentLength = file.length();
            ByteArrayOutputStream outstream = new ByteArrayOutputStream(
                    contentLength > 0 ? (int) contentLength : 1024);
            byte[] buffer = new byte[4096];
            int len;
            while ((len = bufferedInputStream.read(buffer)) > 0) {
                outstream.write(buffer, 0, len);
            }
            outstream.close();
            bufferedInputStream.close();
            jsonString = outstream.toString();
        } catch (FileNotFoundException e) {
            Utils.error(FileUtils.class, Utils.getStackTrace(e));
            jsonString = null;
        } catch (IOException e) {
            Utils.error(FileUtils.class, Utils.getStackTrace(e));
            jsonString = null;
        }

        return jsonString;
    }

    public static byte[] fileToByteArray(File file) {
        try {
            return StreamToByteArray(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] StreamToByteArray(InputStream is) {
        byte[] ret = null;
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] temp = new byte[4096];
            int size = 0;
            while ((size = is.read(temp)) != -1) {
                out.write(temp, 0, size);
            }
            is.close();
            out.close();
            ret = out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    public static String fileToString(File file) {
        try {
            return new String(fileToByteArray(file), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }

    public static boolean byteArrayToFile(byte[] bytes, String filePath) {
        if (bytes == null || bytes.length <= 0 || TextUtils.isEmpty(filePath)) {
            return false;
        }

        try {
            BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(bytes));
            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filePath,
                    false));
            byte[] temp = new byte[4096];
            int size = 0;
            while ((size = in.read(temp)) != -1) {
                out.write(temp, 0, size);
            }
            in.close();
            out.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static String streamToString(InputStream is) {
        StringBuffer sb = new StringBuffer();

        try {
            InputStreamReader isreader = new InputStreamReader(is);
            BufferedReader buffReader = new BufferedReader(isreader);
            String line = buffReader.readLine();
            while (line != null) {
                sb.append(line.trim());
                line = buffReader.readLine();
            }
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    public static String readFile(String path) {
        String result = null;
        InputStreamReader in;
        try {

            in = new FileReader(path);
            StringBuffer sb = new StringBuffer();
            char[] buffer = new char[1024];
            int length = 0;
            while ((length = in.read(buffer)) > 0) {
                sb.append(buffer, 0, length);
            }
            in.close();
            result = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static String readAssetFile(Context context, String fileName) {
        String result = null;
        InputStream in;
        try {
            in = context.getAssets().open(fileName);
            StringBuffer sb = new StringBuffer();
            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = in.read(buffer)) > 0) {
                sb.append(new String(buffer, 0, length));
            }
            in.close();
            result = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void writeFileFromStream(InputStream stream, String filePath)
            throws FileNotFoundException, IOException {
        Utils.copyStream(stream, new FileOutputStream(filePath));
    }

    public static boolean copyFile(File fromPath, File toPath) {
        if (fromPath != null && fromPath.exists() && toPath != null) {
            InputStream is = null;
            try {
                if (toPath.exists()) {
                    toPath.delete();
                }
                is = new FileInputStream(fromPath);
                OutputStream ops = new FileOutputStream(toPath);
                int len = 0;
                byte[] buffer = new byte[4096];
                while (len != -1) {
                    len = is.read(buffer);
                    if (len > 0) {
                        ops.write(buffer, 0, len);
                    }
                }
                if (is != null) {
                    is.close();
                }
                if (ops != null) {
                    ops.close();
                }
                return true;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return false;
    }

    public static boolean deleteFile(String path) {
        return new File(path).delete();
    }

    public static void deleteDir(File dir) {
        if (dir != null && dir.exists() && dir.isDirectory()) {
            File files[] = dir.listFiles();
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDir(file);
                } else {
                    file.delete();
                }
            }
            dir.delete();
        }
    }

    public static boolean isZeroSize(String path) {
        return new File(path).length() == 0;
    }

    public static Drawable getApkIcon(Context context, String apkPath) {
        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
            if (info != null) {
                ApplicationInfo appInfo = info.applicationInfo;
                appInfo.sourceDir = apkPath;
                appInfo.publicSourceDir = apkPath;
                return appInfo.loadIcon(pm);
            }
        } catch (Throwable e) {
            BLog.e("ApkIconLoader", e.toString());
        }
        return null;
    }

    @SuppressWarnings("unused")
    public static String getSdCacheMapDir(Context context) {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            java.io.File autonaviDir = new java.io.File(FileConstants.LOCAL_PATH_BASE);
            boolean result = false;
            if (!autonaviDir.exists()) {
                result = autonaviDir.mkdir();
            }
            java.io.File minimapDir = new java.io.File(autonaviDir,
                    "offlineMap");
            if (!minimapDir.exists()) {
                result = minimapDir.mkdir();
            }
            return minimapDir.toString() + "/";
        } else {
            return "";
        }
    }

    public static void Serializable2File(Serializable object, String filename) throws IOException {
        if (isFileExist(filename))
        {
            deleteFile(filename);
        }
        createFileInSDCard(filename);
        FileOutputStream fos = new FileOutputStream(filename);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(object);
        oos.close();
    }

    @SuppressWarnings("resource")
    public static Object File2erializable(String filename) throws StreamCorruptedException,
            IOException,
            ClassNotFoundException {
        Object mObject = null;
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        mObject = ois.readObject();
        return mObject;
    }

}
